package com.kapcb.log.filter;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import com.kapcb.common.constant.LogConstant;
import com.kapcb.context.core.ApplicationThreadContextHolder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * <a>Title: TraceFilter </a>
 * <a>Author: kapcb <a>
 * <a>Description: TraceFilter <a>
 *
 * @author Kpacb
 * @version 1.0
 * @date 2024/5/25 13:39
 * @since 1.0
 */
public class TraceFilter extends OncePerRequestFilter {

    private static final String HOST_ADDRESS = NetUtil.getLocalhost().getHostAddress();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String traceId = getTraceId(request, response);
        // 设置到 MDC 中
        MDC.put(LogConstant.LOG_TRACE_ID, traceId);
        MDC.put(LogConstant.LOG_IP, HOST_ADDRESS);
        // 设置到线程上线文中
        ApplicationThreadContextHolder.put(LogConstant.LOG_TRACE_ID, traceId);
        // 设置到响应头中
        response.setHeader(LogConstant.LOG_TRACE_ID, traceId);
        filterChain.doFilter(request, response);
    }

    private String getTraceId(HttpServletRequest request, HttpServletResponse response) {
        // 先从请求头中获取 traceId
        String traceId = request.getHeader(LogConstant.LOG_TRACE_ID);
        if (StringUtils.isBlank(traceId)) {
            // 再从响应头中获取，可能在此之前有人设置 traceId 到响应头中
            traceId = response.getHeader(LogConstant.LOG_TRACE_ID);
            if (StringUtils.isBlank(traceId)) {
                // 请求头中没有则使用后端自己生成的 traceId
                traceId = IdUtil.fastUUID().replace("-", "") + "." + Thread.currentThread().getId() + "." + System.currentTimeMillis();
            }
        }
        return traceId;
    }
}
